using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Silverlight.Testing;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Rhino.Mocks;
using SLNGP.Core.GeneticPrograms;
using SLNGP.Core.Individuals;
using SLNGP.Core.Run;
using SLNGP.Core.StopRun;
using SLNGP.Core.Test;

namespace SLNGP.Test.CoreTests.StopRun
{
    [TestClass]
    [Tag("StopRunConditions")]
    public class StopRunConditions_Test : UnitTestBase<IStopRunConditions, StopRunConditions>
    {
        #region UnitTestBase methods
        [ClassInitialize]
        public static void ClassInitialize(TestContext testContext)
        {
            UnitTestBase<IStopRunConditions, StopRunConditions>.ClassInitialize(testContext);
        }

        [ClassCleanup]
        public static void ClassCleanup()
        {
            UnitTestBase<IStopRunConditions, StopRunConditions>.ClassCleanup();
        }

        private IGeneticProgrammingRunResults _lastRunResultsMock = null;
        [TestInitialize]
        public override void TestInitialize()
        {
            base.TestInitialize();

            _lastRunResultsMock = mocks.DynamicMock<IGeneticProgrammingRunResults>();
            var mockGP = mocks.DynamicMock<IGeneticProgram>();
            curElement.Parent = mockGP;

            Expect.Call(mockGP.LastRunResults).Return(_lastRunResultsMock).Repeat.Any();
        }

        [TestCleanup]
        public override void TestCleanup()
        {
            base.TestCleanup();
        }
        #endregion UnitTestBase methods

        [TestMethod]
        public void CurrentGenerationMockedAndGenerationStopConditionSpecified_InvokeShould_ConditionIsInvokedAndReturned()
        {
            // state - CurrentGenerationMockedAndGenerationStopConditionSpecified
            var mock = mocks.DynamicMock<IGeneration>();
            SetupResult.For(_lastRunResultsMock.CurrentGeneration).Return(mock);

            curElement.GenerationStopCondition = (generation) =>
                                                     {
                                                         Assert.IsTrue(generation == mock);
                                                         return true;
                                                     };

            // action - InvokeShould
            mocks.ReplayAll();
            var result = curElement.ShouldStopBecauseOfGenerationStopCondition();

            // Expectation - ConditionIsInvokedAndReturned
            Assert.IsTrue(result.HasValue && result.Value);
            mocks.VerifyAll();
        }

        [TestMethod]
        public void GenerationStopConditionNull_InvokeShould_ReturnsNull()
        {
            // state - GenerationStopConditionNull
            curElement.GenerationStopCondition = null;

            // action - InvokeShould
            mocks.ReplayAll();
            var result = curElement.ShouldStopBecauseOfGenerationStopCondition();

            // Expectation - ReturnsNull
            Assert.IsTrue(!result.HasValue);
            mocks.VerifyAll();
        }

        [TestMethod]
        public void IndividualStopConditionNull_InvokeShould_ReturnsNull()
        {
            // state - GenerationStopConditionNull
            curElement.IndividualStopCondition = null;

            // action - InvokeShould
            mocks.ReplayAll();
            var result = curElement.ShouldStopBecauseOfIndividualStopCondition();

            // Expectation - ReturnsNull
            Assert.IsTrue(!result.HasValue);
            mocks.VerifyAll();
        }

        [TestMethod]
        public void ComplexStopConditionNull_InvokeShould_ReturnsNull()
        {
            // state - GenerationStopConditionNull
            curElement.ComplexStopCondition = null;

            // action - InvokeShould
            mocks.ReplayAll();
            var result = curElement.ShouldStopBecauseOfComplexStopCondition();

            // Expectation - ReturnsNull
            Assert.IsTrue(!result.HasValue);
            mocks.VerifyAll();
        }

        [TestMethod]
        public void MaxGenerationsCountNull_InvokeShould_ReturnsNull()
        {
            // state - GenerationStopConditionNull
            curElement.MaxGenerationsCount = null;

            // action - InvokeShould
            mocks.ReplayAll();
            var result = curElement.ShouldStopBecauseOfMaxGenerationsCount();

            // Expectation - ReturnsNull
            Assert.IsTrue(!result.HasValue);
            mocks.VerifyAll();
        }

        [TestMethod]
        public void Ctor_CheckConditions_AllConditionsAreNull()
        {
            // state - Ctor
            // action - CheckConditions
            // Expectation - AllConditionsAreNull

            foreach (var propertyInfo in curElement.GetType()
                                                   .GetProperties()
                                                   .Where(p => p.PropertyType.IsSubclassOf(typeof(Delegate))))
            {
                Assert.IsNull(propertyInfo.GetValue(curElement, new object[] { }));
            }
        }

        [TestMethod]
        public void Has5GenerationsAndMaxGenerationCount5_ShouldStopIsInvoked_ReturnsTrue()
        {
            // state - Has5GenerationsAndMaxGenerationCount5
            SetupResult.For(_lastRunResultsMock.Generations).Return(new List<IGeneration>()
                                                                        {
                                                                            mocks.DynamicMock<IGeneration>(),
                                                                            mocks.DynamicMock<IGeneration>(),
                                                                            mocks.DynamicMock<IGeneration>(),
                                                                            mocks.DynamicMock<IGeneration>(),
                                                                            mocks.DynamicMock<IGeneration>()
                                                                        });
            curElement.MaxGenerationsCount = 5;

            // action - ShouldStopIsInvoked
            mocks.ReplayAll();
            var result = curElement.ShouldStopBecauseOfMaxGenerationsCount();

            // Expectation - ReturnsTrue
            Assert.IsTrue(result.HasValue && result.Value);
            mocks.VerifyAll();
        }

        [TestMethod]
        public void Has4GenerationsAndMaxGenerationCount5_ShouldStopIsInvoked_ReturnsFalse()
        {
            // state - Has5GenerationsAndMaxGenerationCount5
            SetupResult.For(_lastRunResultsMock.Generations).Return(new List<IGeneration>()
                                                                        {
                                                                            mocks.DynamicMock<IGeneration>(),
                                                                            mocks.DynamicMock<IGeneration>(),
                                                                            mocks.DynamicMock<IGeneration>(),
                                                                            mocks.DynamicMock<IGeneration>(),
                                                                        });
            curElement.MaxGenerationsCount = 5;

            // action - ShouldStopIsInvoked
            mocks.ReplayAll();
            var result = curElement.ShouldStopBecauseOfMaxGenerationsCount();

            // Expectation - ReturnsTrue
            Assert.IsTrue(result.HasValue && (result.Value == false));
            mocks.VerifyAll();
        }

        [TestMethod]
        // This test has a hard dependency on Generation. 
        public void CurrentGenerationWith2IndividualsAndStopConditionReturnsFalse_ShouldIsInvoked_BothIndividualAreSentToStopCondition()
        {
            // state - CurrentGenerationWith2IndividualsAndStopConditionReturnsFalse
            var mock1 = mocks.DynamicMock<IIndividual>();
            var mock2 = mocks.DynamicMock<IIndividual>();
            SetupResult.For(_lastRunResultsMock.CurrentGeneration).Return(new Generation() {mock1, mock2});

            curElement.IndividualStopCondition = (individual) =>
             {
                 // Expectation - BothIndividualAreSentToStopCondition
                 Assert.IsTrue(individual == mock1 || individual == mock2);
                 return false;
             };

            // action - ShouldIsInvoked
            mocks.ReplayAll();
            var result = curElement.ShouldStopBecauseOfIndividualStopCondition();
            mocks.VerifyAll();
        }

        [TestMethod]
        // This test has a hard dependency on Generation. 
        public void CurrentGenerationWith2IndividualsAndStopConditionReturnsFalse_ShouldIsInvoked_ReturnsFalse()
        {
            // state - CurrentGenerationWith2IndividualsAndStopConditionReturnsFalse
            var mock1 = mocks.DynamicMock<IIndividual>();
            var mock2 = mocks.DynamicMock<IIndividual>();
            SetupResult.For(_lastRunResultsMock.CurrentGeneration).Return(new Generation() { mock1, mock2 });

            curElement.IndividualStopCondition = (individual) =>  false;

            // action - ShouldIsInvoked
            mocks.ReplayAll();
            var result = curElement.ShouldStopBecauseOfIndividualStopCondition();

            // Expectation - ReturnsFalse
            Assert.IsTrue(result.HasValue && (result.Value == false));
            mocks.VerifyAll();
        }

        [TestMethod]
        // This test has a hard dependency on Generation. 
        public void CurrentGenerationWith2IndividualsAndStopConditionReturnsTrueForSecond_ShouldIsInvoked_ReturnsTrue()
        {
            // state - CurrentGenerationWith2IndividualsAndStopConditionReturnsTrueForSecond
            var mock1 = mocks.DynamicMock<IIndividual>();
            var mock2 = mocks.DynamicMock<IIndividual>();
            SetupResult.For(_lastRunResultsMock.CurrentGeneration).Return(new Generation() { mock1, mock2 });

            curElement.IndividualStopCondition = (individual) =>
             {
                 if (individual == mock1) return false;
                 else if (individual == mock2) return true;
                 else return false;
             };

            // action - ShouldIsInvoked
            mocks.ReplayAll();
            var result = curElement.ShouldStopBecauseOfIndividualStopCondition();

            // expectation - ReturnsTrue
            Assert.IsTrue(result.HasValue && (result.Value == true));
            mocks.VerifyAll();
        }

        [TestMethod]
        public void ComplexStopConditionSpecifiedReturnsFalse_InvokedWithStopConditions_ReturnsFalse()
        {
            // state - ComplexStopConditionSpecifiedReturnsFalse
            curElement.ComplexStopCondition = (stopRunConditions) => 
            {
                Assert.IsTrue(stopRunConditions == curElement);
                return false;
            };

            // action - InvokedWithStopConditions
            mocks.ReplayAll();
            var result = curElement.ShouldStopBecauseOfComplexStopCondition();

            // Expectation - ReturnsFalse
            Assert.IsTrue(result.HasValue && (result.Value == false));
            mocks.VerifyAll();
        }

        [TestMethod]
        public void ComplexStopConditionSpecifiedReturnsTrue_Invoked_ReturnsTrue()
        {
            // state - ComplexStopConditionSpecifiedReturnsFalse
            curElement.ComplexStopCondition = (stopRunConditions) => true;

            // action - InvokedWithStopConditions
            mocks.ReplayAll();
            var result = curElement.ShouldStopBecauseOfComplexStopCondition();

            // Expectation - ReturnsFalse
            Assert.IsTrue(result.HasValue && result.Value);
            mocks.VerifyAll();
        }

        [TestMethod]
        public void CanStop_Invoked_AllShouldMethodsAreInvoked()
        {
            // Expectation - AllShouldMethodsAreInvoked
            var element = mocks.StrictMock<StopRunConditions>();

            Expect.Call(element.ShouldStopBecauseOfComplexStopCondition()).Return(null);
            Expect.Call(element.ShouldStopBecauseOfGenerationStopCondition()).Return(null);
            Expect.Call(element.ShouldStopBecauseOfIndividualStopCondition()).Return(null);
            Expect.Call(element.ShouldStopBecauseOfMaxGenerationsCount()).Return(null);

            // state - CanStop
            // action - Invoked
            mocks.ReplayAll();
            element.CanStop();
            mocks.VerifyAll();
        }

        [TestMethod]
        public void OpearatorIsAnyAndAnyOneConditionIsTrue_CanStop_ReturnsTrue()
        {
            // state - OneConditionIsTrue
            curElement.StopRunConditionsOpearator = StopRunConditionsOpearator.Any;
            curElement.ComplexStopCondition = (x) => true;

            // action - CanStop
            var result = curElement.CanStop();

            // Expectation - ReturnsTrue
            Assert.IsTrue(result);
        }

        [TestMethod]
        public void OpearatorIsAnyAndAllConditionsAreFalse_CanStop_ReturnsFalse()
        {
            // state - OpearatorIsAnyAndAllConditionsAreFalse
            curElement.StopRunConditionsOpearator = StopRunConditionsOpearator.Any;
            curElement.ComplexStopCondition = (x) => false;
            curElement.GenerationStopCondition = (x) => false;

            // action - CanStop
            var result = curElement.CanStop();

            // Expectation - ReturnsFalse
            Assert.IsTrue(result == false);
        }

        [TestMethod]
        public void OpearatorIsAnyAndAll2ConditionsAreFalse1IsTrue_CanStop_ReturnsTrue()
        {
            // state - OpearatorIsAnyAndAll2ConditionsAreFalse1IsTrue
            curElement.StopRunConditionsOpearator = StopRunConditionsOpearator.Any;
            curElement.ComplexStopCondition = (x) => false;
            curElement.GenerationStopCondition = (x) => false;
            curElement.IndividualStopCondition = (x) => true;
            SetupResult.For(_lastRunResultsMock.CurrentGeneration).Return(new Generation() { null });

            // action - CanStop
            mocks.ReplayAll();
            var result = curElement.CanStop();

            // Expectation - ReturnsTrue
            Assert.IsTrue(result == true);
        }


        [TestMethod]
        public void OpearatorIsAllAndAllOneConditionIsTrue_CanStop_ReturnsTrue()
        {
            // state - OneConditionIsTrue
            curElement.StopRunConditionsOpearator = StopRunConditionsOpearator.All;
            curElement.ComplexStopCondition = (x) => true;

            // action - CanStop
            var result = curElement.CanStop();

            // Expectation - ReturnsTrue
            Assert.IsTrue(result);
        }

        [TestMethod]
        public void OpearatorIsAllAndAllConditionsAreFalse_CanStop_ReturnsFalse()
        {
            // state - OpearatorIsAllAndAllConditionsAreFalse
            curElement.StopRunConditionsOpearator = StopRunConditionsOpearator.All;
            curElement.ComplexStopCondition = (x) => false;
            curElement.GenerationStopCondition = (x) => false;

            // action - CanStop
            var result = curElement.CanStop();

            // Expectation - ReturnsFalse
            Assert.IsTrue(result == false);
        }

        [TestMethod]
        public void OpearatorIsAllAndAll2ConditionsAreFalse1IsTrue_CanStop_ReturnsFalse()
        {
            // state - OpearatorIsAllAndAll2ConditionsAreFalse1IsTrue
            curElement.StopRunConditionsOpearator = StopRunConditionsOpearator.All;
            curElement.ComplexStopCondition = (x) => false;
            curElement.GenerationStopCondition = (x) => false;
            curElement.IndividualStopCondition = (x) => true;
            SetupResult.For(_lastRunResultsMock.CurrentGeneration).Return(new Generation() { null });

            // action - CanStop
            mocks.ReplayAll();
            var result = curElement.CanStop();

            // Expectation - ReturnsFalse
            Assert.IsTrue(result == false);
        }
    }
}
